<template>
	<view class="vi_drawer" :class="'vi_drawer_'+inPoint" :style="mainStyle" v-if="enable" @touchmove.stop.prevent>
		<view class="vi_drawer_mask" :class="{'vi_drawer_act': showDrawer}" :style="maskStyle" v-if="setting.useMask" @tap="onMaskClick" />
		<view class="vi_drawer_content" :class="{'vi_drawer_invalid':!showDrawer}" :style="contentStyle">
			<slot />
		</view>
	</view>
</template>

<script>
	export default {
		name: 'viDrawer',
		props: {
			position:{
				type:[String,null],
				default:""
			},
			top:{
				type:[String,Number,null],
				default:""
			},
			bottom:{
				type:[String,Number,null],
				default:""
			},
			//打开位置，只在初始化生效
			point:{
				type:[String,null],
				default:""
			},
			bgColor:{
				type:[String,null],
				default:""
			},
			//使用蒙版
			useMask:{
				type:[Boolean,null],
				default:null
			},
			//点击遮罩关闭
			maskClick:{
				type:[Boolean,null],
				default:null
			},
			maskBgColor:{
				type:[String,null],
				default:""
			},
			//抽屉宽度
			width:{
				type:[String,null],
				default:""
			},
			minWidth:{
				type:[String,null],
				default:null
			},
			//抽屉高度
			height:{
				type:[String,null],
				default:""
			},
			zIndex:{
				type:[Number,String,null],
				default:null
			}
		},
		data() {
			return {
				duration: 300,			//动画持续时长，须与css的transition变量一致
				enable: false,			//启用
				showDrawer: false,		//显示
				openTimer:null,			//打开计时器，用来确定提交事件
				closeTimer:null,		//关闭计时器，用来确定提交事件
				inPoint:"",
				pointType: ["top", "center", "bottom", "left", "right"],
			}
		},
		computed:{
			//将默认值内含到css、计算属性等地方，只内含真值
			//规避特殊使用的情况下，由prop传入undefined、null等无效数据导致的，默认值失效问题。例如组件嵌套且需要组件间参数传递
			//HBuilder X3.3.13; 微信开发者工具stable 1.05.2111300
			//微信小程序会对传入的undefined、null值根据参数类型输出不同空值(false、""、null、0)，参数类型为null或未指定参数类型则输出null
			//H5会对传入的undefined取默认值，未设默认值则输出undefined。对传入的null值固定输出null
			//做参数传递时需警惕两者行为不同而造成的陷阱，主要问题出现在微信小程序的空值转化，输出非用户传入的空值、假值，使默认真值丢失
			//兼容空值取默认值的可行方案目前为，参数类型加入null如[Boolean,null]，判断传入参数是否为定义的类型，是则使用，否则赋予默认值
			setting(){
				return {
					useMask: this.$api.isBoolean(this.useMask)? this.useMask :true,
					position: this.position ||"fixed",
					maskClick: this.$api.isBoolean(this.maskClick)? this.maskClick :true,
					maskBgColor: this.maskBgColor ||"rgba(0,0,0,0.4)",
					width: this.width ||(["left","right"].includes(this.inPoint)?"75%":""),
					minWidth: this.$api.isDefined(this.minWidth)? this.minWidth :"20%",
					zIndex: this.$api.isValue(this.zIndex)? Number(this.zIndex)||0 :99,
				}
			},
			mainStyle(){
				let res={
					"z-index": this.setting.zIndex
				};
				let position = this.setting.position;
				if(position){
					res["position"] = position
					if(position!="fixed"){
						res["width"] = "100%"
					}
				}
				if(this.top){
					res["top"] = this.top
				}
				if(this.bottom){
					res["bottom"] = this.bottom
				}
				return this.$api.objToStr(res)
			},
			maskStyle(){
				let res={
					"background-color": this.setting.maskBgColor,
					"z-index": this.setting.zIndex -1
				}
				return this.$api.objToStr(res)
			},
			contentStyle(){
				let res={
						"z-index": this.setting.zIndex
					},
					width = this.setting.width,
					minWidth = this.setting.minWidth,
					height = this.height;
				width? res["width"]=width :"";
				minWidth? res["min-width"]=minWidth :"";
				height? res["height"]=height :"";
				res["background-color"]= this.bgColor? this.bgColor :"#fff";
				return this.$api.objToStr(res)
			}
		},
		methods: {
			open(options) {
				//打开中或已打开，退出
				if((this.enable&&this.openTimer)||this.showDrawer){
					this.$emit("opened")
					return
				}
				//如果有关闭计时器，清除
				if(this.closeTimer){
					clearTimeout(this.closeTimer);
					this.closeTimer =null;
				}
				let {point} = options||{};
				if(point && this.pointType.includes(point)){
					this.inPoint = point
				}
				this.enable = true;
				//延迟执行动画，否则不显示动画只闪烁，非H5给予较大值
				let delay = 50;
				// #ifndef H5
				delay = 100
				// #endif
				setTimeout(()=>{
					this.showDrawer = true;
					this.openTimer = setTimeout(()=>{
						this.openTimer = null;
						this.$emit("opened")
					},this.duration)
				}, delay)
				//下一帧提交变更事件，确保内容已创建
				this.$nextTick(()=>{
					this.$emit("change",true)
				})
			},
			close() {
				//关闭中或已关闭，退出
				if((!this.showDrawer&&this.closeTimer)||!this.enable){
					this.$emit("closed");
					return
				}
				//如果有打开计时器，清除
				if(this.openTimer){
					clearTimeout(this.openTimer);
					this.openTimer =null;
				}
				this.showDrawer = false;
				//动画完成后卸载
				this.closeTimer = setTimeout(()=>{
					this.enable = false;
					this.closeTimer = null;
					this.$emit("closed");
				},this.duration)
				//提交变更事件
				this.$emit("change",false)
			},
			onMaskClick(){
				this.$emit("maskClick")
				if(this.setting.maskClick){
					this.close()
				}
			},
		},
		watch:{
			"point":{
				immediate: true,
				handler(newVal){
					this.inPoint = this.pointType.includes(newVal)?newVal:"left";
				}
			}
		},
	}
</script>

<style lang="scss">
$transition:.3s;
.vi_drawer {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	overflow: hidden;
	display: flex;
	.vi_drawer_mask{
		opacity: 0;
		position: absolute;
		top: 0;
		left: 0;
		bottom: 0;
		right: 0;
		background-color: rbga(0,0,0,0.4);
		transition: opacity $transition;
		&.vi_drawer_act{
			opacity: 1;
		}
	}
	.vi_drawer_content{
		position: relative;
		transition: $transition;
	}
	&.vi_drawer_left{
		justify-content: flex-start;
		align-items: center;
		>.vi_drawer_content{
			height: 100%;
		}
		>.vi_drawer_invalid{
			transform: translateX(-100%);
		}
	}
	&.vi_drawer_right{
		justify-content: flex-end;
		align-items: center;
		>.vi_drawer_content{
			height: 100%;
		}
		>.vi_drawer_invalid{
			transform: translateX(100%);
		}
	}
	&.vi_drawer_top{
		justify-content: center;
		align-items: flex-start;
		>.vi_drawer_content{
			width: 100%;
		}
		>.vi_drawer_invalid{
			transform: translateY(-100%);
		}
	}
	&.vi_drawer_bottom{
		justify-content: center;
		align-items: flex-end;
		>.vi_drawer_content{
			width: 100%;
		}
		>.vi_drawer_invalid{
			transform: translateY(100%);
		}
	}
	&.vi_drawer_center{
		justify-content: center;
		align-items: center;
		>.vi_drawer_invalid{
			opacity: 0;
			transform: scale(0.9);
		}
	}
}
</style>
